package org.example.graph;

import com.google.common.graph.*;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

@SuppressWarnings("all")
public class GuavaGraph {

    public static void main(String[] args) {
        MutableGraph<Integer> mg = build();
        addElem(mg);
        Iterable<Integer> dfs = Traverser.forGraph(mg).depthFirstPostOrder(1);
        Traverser.forGraph(mg).depthFirstPreOrder(1).forEach(x -> System.out.println(x));
        Iterable<Integer> bfs = Traverser.forGraph(mg).breadthFirst(1);
        Iterator<Integer> dit = dfs.iterator();
        while (dit.hasNext()) {
            System.out.print(dit.next()+"->");
        }
        System.out.println();
        Iterator<Integer> bit = bfs.iterator();
        while (bit.hasNext()) {
            System.out.print(bit.next()+"->");
        }
        // [1, 2, 3, 5, 4]
        showNodes(mg);
        // [<1 -> 4>, <1 -> 2>, <2 -> 3>, <3 -> 5>, <4 -> 5>]
        showEdges(mg);
        // curr node: 1 processor: []
        // curr node: 2 processor: [1]
        // curr node: 3 processor: [2]
        // curr node: 5 processor: [4, 3]
        // curr node: 4 processor: [1]
        showProcessorors(mg);
        // curr node: 1 degred: 2 inDegree: 0 outDegree: 2
        // curr node: 2 degred: 2 inDegree: 1 outDegree: 1
        // curr node: 3 degred: 2 inDegree: 1 outDegree: 1
        // curr node: 5 degred: 2 inDegree: 2 outDegree: 0
        // curr node: 4 degred: 2 inDegree: 1 outDegree: 1
        showDegree(mg);
        /**
         * curr node: 1 connecting with N1: false
         * curr node: 1 connecting with N2: true
         * curr node: 1 connecting with N3: false
         * curr node: 1 connecting with N4: true
         * curr node: 1 connecting with N5: false
         * curr node: 2 connecting with N1: false
         * curr node: 2 connecting with N2: false
         * curr node: 2 connecting with N3: true
         * curr node: 2 connecting with N4: false
         * curr node: 2 connecting with N5: false
         * curr node: 3 connecting with N1: false
         * curr node: 3 connecting with N2: false
         * curr node: 3 connecting with N3: false
         * curr node: 3 connecting with N4: false
         * curr node: 3 connecting with N5: true
         * curr node: 5 connecting with N1: false
         * curr node: 5 connecting with N2: false
         * curr node: 5 connecting with N3: false
         * curr node: 5 connecting with N4: false
         * curr node: 5 connecting with N5: false
         * curr node: 4 connecting with N1: false
         * curr node: 4 connecting with N2: false
         * curr node: 4 connecting with N3: false
         * curr node: 4 connecting with N4: false
         * curr node: 4 connecting with N5: true
         */
        detectConnection(mg);
        // subGraph: isDirected: true, allowsSelfLoops: false, nodes: [1, 4, 5], edges: [<1 -> 4>, <4 -> 5>]
        MutableGraph subGraph = substract(mg);

    }

    private static MutableGraph substract(MutableGraph<Integer> graph) {
        Set<Integer> subNodes = new HashSet<>();
        subNodes.add(1);
        subNodes.add(4);
        subNodes.add(5);
        MutableGraph<Integer> subGraph = Graphs.inducedSubgraph(graph, subNodes);
        System.out.println("subGraph: " + subGraph);

        return subGraph;

    }

    private static void detectConnection(MutableGraph<Integer> graph) {
        for (Integer each : graph.nodes()) {
            System.out.println("curr node: " + each + " connecting with N1: " + graph.hasEdgeConnecting(each, 1));
            System.out.println("curr node: " + each + " connecting with N2: " + graph.hasEdgeConnecting(each, 2));
            System.out.println("curr node: " + each + " connecting with N3: " + graph.hasEdgeConnecting(each, 3));
            System.out.println("curr node: " + each + " connecting with N4: " + graph.hasEdgeConnecting(each, 4));
            System.out.println("curr node: " + each + " connecting with N5: " + graph.hasEdgeConnecting(each, 5));
        }
    }

    private static void showDegree(MutableGraph<Integer> graph) {
        for (Integer each : graph.nodes()) {
            System.out.println("curr node: " + each + " degred: " + graph.degree(each) +
                    " inDegree: " + graph.inDegree(each) +
                    " outDegree: " + graph.outDegree(each));
            ;
        }
    }

    private static void showProcessorors(MutableGraph<Integer> graph) {
        for (Integer each : graph.nodes()) {
            System.out.println("curr node: " + each + " processor: " + graph.predecessors(each));
            ;
        }
    }

    private static void showEdges(MutableGraph<Integer> graph) {
        Set<EndpointPair<Integer>> edges = graph.edges();
        System.out.println("graph nodes: " + edges.size() + " " + edges);
    }

    private static void showNodes(MutableGraph<Integer> graph) {
        Set<Integer> nodes = graph.nodes();
        System.out.println("graph nodes: " + nodes.size() + " " + nodes);
    }

    private static void addElem(MutableGraph<Integer> graph) {
        Integer n1 = 1;
        Integer n2 = 2;
        Integer n3 = 3;
        Integer n4 = 4;
        Integer n5 = 5;
        Integer n6 = 6;
        Integer n7 = 7;
        Integer n8 = 8;
        // 第一条路径 1->2->3->5
        // 第二条路径 1->4->5
        graph.putEdge(n1, n2);
        graph.putEdge(n2, n3);
        graph.putEdge(n3, n4);
        graph.putEdge(n4, n5);
        graph.putEdge(n2, n6);
        graph.putEdge(n6, n7);
        graph.putEdge(n7, n8);

        System.out.println("graph: " + graph.edges());
    }


    public static MutableGraph<Integer> build() {
        MutableGraph<Integer> mg = GraphBuilder.directed()
                .nodeOrder(ElementOrder.insertion())
                .expectedNodeCount(16)
                .allowsSelfLoops(false)
                .build();
        System.out.println("graph: " + mg);

        return mg;
    }


}


